package com.yixing.tech.common.aop.aspect;

import com.yixing.tech.common.config.IgnoreRequestLogMap;
import com.yixing.tech.common.utils.CommonConstant;
import com.yixing.tech.common.service.CommonService;
import com.yixing.tech.common.vo.s3.UserVO;
import com.yixing.tech.common.base.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 日志记录切面
 */
@Aspect
@Component
@Slf4j
public class LogRecordAspect {

    @Value("${log-obj-id}")
    private String logObjId;

    @Value("${tenant-id: 6204cb763da841718ddd1cf8}")
    private String tenantId;

    @Resource
    private MongoTemplate mongoTemplate;

    private IgnoreRequestLogMap ignoreRequestLogMap = new IgnoreRequestLogMap();

    /**
     * 记录方法执行日志
     */
    @Around("@annotation(org.springframework.web.bind.annotation.RestController)")
    public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();

        // 异步记录日志
        recordLogAsync(result);

        return result;
    }

    @Async
    public void recordLogAsync(Object result) {
        try {
            if (!(result instanceof com.yixing.tech.common.base.BaseResponse)) return;

            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            if (request == null) {
                return;
            }

            Map<String, Object> logMap = new HashMap<>();
            com.yixing.tech.common.base.BaseResponse response = (com.yixing.tech.common.base.BaseResponse) result;
            String path = request.getRequestURI();
            String method = request.getMethod();
            int resultCode = response.getCode();
            logMap.put("结果", resultCode);
            logMap.put("路径", path);
            logMap.put("IP地址", getIp(request));
            logMap.put("类型", path.contains("obj/entity") ? "三方" : "平台");
            logMap.put("请求类型", method);
            logMap.put("createTime", new Date());
            logMap.put("tenantId", tenantId);

            try {
                // 这里需要调用用户工具类获取用户信息
                UserVO userVO = getCurrentUser();
                if (userVO != null) {
                    logMap.put("createName", userVO.getName());
                    logMap.put("createId", userVO.getId());
                    logMap.put("tenantId", userVO.getTenantId());
                }
            } catch (Exception e) {
                log.error("获取用户信息失败", e);
            }

            boolean logable = true;
            for (Map.Entry<String, String> entry : ignoreRequestLogMap.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (!path.contains(key)) continue;
                if (null == value || method.equals(value)) {
                    logable = false;
                    break;
                }
            }
            if (!logable) return;

            mongoTemplate.insert(logMap, "entity_" + logObjId);
        } catch (Exception e) {
            log.error("记录日志失败", e);
        }
    }

    private String getIp(HttpServletRequest request) {
        String ip = request.getHeader(CommonConstant.HEADERS_IP);
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    // 需要从工具类获取当前用户
    private UserVO getCurrentUser() throws BusinessException {
        // 这个方法将从新的工具类中调用
        return CommonService.getApiUser();
    }
}
